{
 "metadata": {
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.12-final"
  },
  "orig_nbformat": 2,
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3",
   "language": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2,
 "cells": [
  {
   "source": [
    "# 第二部分：机器学习基础篇（上）"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 1、损失函数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 线性回归损失"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "mse = lambda yi, fi: np.sum((yi - fi) ** 2)\n",
    "\n",
    "mae = lambda yi, fi: np.sum(np.abs(yi - fi))\n",
    "\n",
    "huber = lambda yi, fi, delta=2: np.where(np.abs(yi - fi) < delta, .5 * (yi - fi) ** 2, delta * (np.abs(yi - fi)) - .5 * delta)"
   ]
  },
  {
   "source": [
    "### Hinge 损失函数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "hinge = lambda yi, fi: np.max(0, 1 - fi * xi)"
   ]
  },
  {
   "source": [
    "### 指数损失"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "eloss = lambda yi, fi: np.math.exp(-yi * fi)"
   ]
  },
  {
   "source": [
    "### 交叉熵损失"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "cross_entropy = lambda yi, fi: -np.math.log(fi) if yi == 1 else -np.math.log(1 - fi)"
   ]
  },
  {
   "source": [
    "## 2、交叉验证"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 随机划分数据"
   ],
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "train: [3 4 5 6], test: [1 2]\ntrain: [1 2 4 5], test: [3 6]\ntrain: [1 2 3 6], test: [4 5]\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import KFold\n",
    "\n",
    "# 数据示例\n",
    "X = np.arange(1, 7)\n",
    "# 数据划分\n",
    "kfold = KFold(n_splits = 3, shuffle = True, random_state = 42)\n",
    "for train, test in kfold.split(X):\n",
    "    print('train: {}, test: {}'.format(X[train], X[test]))"
   ]
  },
  {
   "source": [
    "### 使用分层划分，保证y同分布"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "from sklearn.model_selection import StratifiedKFold\n",
    "y = np.array([0, 0, 0, 1, 1, 1])\n",
    "skf = StratifiedKFold(n_splits = 3, shuffle = True, random_state = 42)\n",
    "for train, test in kfold.split(X, y):\n",
    "    print('train: {}, test: {}'.format(X[train], X[test]))"
   ],
   "cell_type": "code",
   "metadata": {},
   "execution_count": 58,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "train: [3 4 5 6], test: [1 2]\ntrain: [1 2 4 5], test: [3 6]\ntrain: [1 2 3 6], test: [4 5]\n"
     ]
    }
   ]
  },
  {
   "source": [
    "### 使用cross_val_score做交叉验证"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Score: 0.9707602339181286, CV Score: 0.9454933630372228\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import load_breast_cancer\n",
    "from sklearn.model_selection import train_test_split, cross_val_score\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "# 加载数据\n",
    "bc = load_breast_cancer()\n",
    "X = bc.data\n",
    "y = bc.target\n",
    "# 构建模型\n",
    "clf = LogisticRegression()\n",
    "# 划分数据\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3, random_state=42)\n",
    "# 模型训练\n",
    "clf.fit(X_train, y_train)\n",
    "# 模型预测得分\n",
    "score = clf.score(X_test, y_test)\n",
    "# 交叉验证\n",
    "cv_scores = cross_val_score(clf, X, y, cv=3, scoring='accuracy')\n",
    "\n",
    "print('Score: {}, CV Score: {}'.format(score, cv_score))"
   ]
  },
  {
   "source": [
    "### 使用交叉验证选择参数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "array([0.94202764, 0.95256948, 0.95432386])"
      ]
     },
     "metadata": {},
     "execution_count": 66
    }
   ],
   "source": [
    "from sklearn.linear_model import LogisticRegressionCV\n",
    "\n",
    "clf = LogisticRegressionCV(Cs = [1, 10, 100], cv=5, scoring='accuracy')\n",
    "# 拟合\n",
    "clf.fit(X, y)\n",
    "# 输出5x3矩阵\n",
    "scores = clf.scores_[1]\n",
    "# 查看5组平均效果\n",
    "scores.mean(axis=0)\n",
    "# 输出3个参数5轮平均的accuracy，正则参数C=100的效果最好，所以选择它"
   ]
  },
  {
   "source": [
    "### 使用交叉验证选择模型"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "0.9279459711224964"
      ]
     },
     "metadata": {},
     "execution_count": 68
    }
   ],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "\n",
    "clf = KNeighborsClassifier()\n",
    "# 5-fold\n",
    "scores = cross_val_score(clf, X, y, cv=5, scoring='accuracy')\n",
    "# 均值\n",
    "scores.mean()\n",
    "# 相比上述调过参数的逻辑回归来说，KNN算法表现差一些，所以选择逻辑回归"
   ]
  }
 ]
}